﻿//*********************************************************
//
// Copyright (c) Microsoft. All rights reserved.
//
//*********************************************************

#pragma once
#include "pch.h"
#include "D3DPanel.h"
#include "DirectXHelper.h"

#include <DirectXMath.h>
#include <DirectXColors.h>
#include <math.h>
#include <ppltasks.h>
#include <windows.ui.xaml.media.dxinterop.h>

using namespace Microsoft::WRL;
using namespace Platform;
using namespace Windows::ApplicationModel;
using namespace Windows::Foundation;
using namespace Windows::Foundation::Collections;
using namespace Windows::Graphics::Display;
using namespace Windows::System::Threading;
using namespace Windows::UI;
using namespace Windows::UI::Core;
using namespace Windows::UI::Input::Inking;
using namespace Windows::Storage::Streams;
using namespace Windows::UI::Xaml;
using namespace Windows::UI::Xaml::Input;
using namespace Windows::UI::Xaml::Media;
using namespace Windows::UI::Xaml::Interop;
using namespace Concurrency;
using namespace DirectX;
using namespace D2D1;
using namespace SharpDepend_UWP_DirectXInterop;
using namespace DX;

D3DPanel::D3DPanel() :
    m_degreesPerSecond(45),
    m_indexCount(0)
{
    critical_section::scoped_lock lock(m_criticalSection);
    CreateDeviceIndependentResources();
    CreateDeviceResources();
    CreateSizeDependentResources();
}

D3DPanel::~D3DPanel()
{

}

/*
void SharpDepend_UWP_DirectXInterop::D3DPanel::OnBeginDraw()
{

}

void SharpDepend_UWP_DirectXInterop::D3DPanel::OnDrawRectangle(float x1, float y1, float x2, float y2, float r, float g, float b, float a, int textureId, float td_x1, float td_y1, float td_x2, float td_y2, int textureWidth, int textureHeight)
{
	Batch batch;
	batch.Type = Batch::ShapeType::Rectangle;
	batch.rectangle.X = x1;
	batch.rectangle.Y = y1;
	batch.rectangle.Z = x2;
	batch.rectangle.W = y2;
	batch.textureCoords.X = td_x1;
	batch.textureCoords.Y = td_y1;
	batch.textureCoords.Z = td_x2;
	batch.textureCoords.W = td_y2;
	batch.textureWidth = textureWidth;
	batch.textureHeight = textureHeight;
	batch.color.R = r;
	batch.color.G = g;
	batch.color.B = b;
	batch.color.A = a;
	batch.textureId = textureId;

	mBatch.push_back(batch);
}

void SharpDepend_UWP_DirectXInterop::D3DPanel::OnDrawLine(float x1, float y1, float x2, float y2, float r, float g, float b, float a)
{
	Batch batch;
	batch.Type = Batch::ShapeType::Line;
	batch.rectangle = Vector4();
	batch.rectangle.X = x1;
	batch.rectangle.Y = y1;
	batch.rectangle.Z = x2;
	batch.rectangle.W = y2;
	batch.color.R = r;
	batch.color.G = g;
	batch.color.B = b;
	batch.color.A = a;
	batch.textureId = -1;

	mBatch.push_back(batch);
}

void SharpDepend_UWP_DirectXInterop::D3DPanel::OnDrawCircle(float x, float y, float radius, float r, float g, float b, float a)
{
	Batch batch;
	batch.Type = Batch::ShapeType::Circle;
	batch.rectangle = Vector4();
	batch.rectangle.X = x;
	batch.rectangle.Y = y;
	batch.rectangle.Z = radius;
	batch.color.R = r;
	batch.color.G = g;
	batch.color.B = b;
	batch.color.A = a;
	batch.textureId = -1;

	mBatch.push_back(batch);
}

void SharpDepend_UWP_DirectXInterop::D3DPanel::OnDrawTriangles(Vector2Double* vertices, int verticesLength, unsigned short* indices, int indicesLength, ColorUInt* colors, int colorLength)
{
	Batch batch;

	batch.Type = Batch::ShapeType::Triangles;
	batch.vertices = vertices;
	batch.verticesLength = verticesLength;
	batch.indices = indices;
	batch.indicesLength = indicesLength;
	batch.colors = colors;
	batch.colorLength = colorLength;

	mBatch.push_back(batch);
}

const float midnightBlue[] = { 0.0f, 0.0f, 0.0f, 1.000f };

inline double Distance(double dX0, double dY0, double dX1, double dY1)
{
	return sqrt((dX1 - dX0)*(dX1 - dX0) + (dY1 - dY0)*(dY1 - dY0));
}

void SharpDepend_UWP_DirectXInterop::D3DPanel::OnEndDraw()
{
	if (!m_loadingComplete)
	{
		return;
	}

	mMutes.lock();
	m_d3dContext->ClearRenderTargetView(
		m_renderTargetView.Get(),
		midnightBlue
		);

	m_d3dContext->ClearDepthStencilView(
		m_depthStencilView.Get(),
		D3D11_CLEAR_DEPTH,
		1.0f,
		0
		);

	m_d3dContext->OMSetRenderTargets(
		1,
		m_renderTargetView.GetAddressOf(),
		m_depthStencilView.Get()
		);

	// Just to trigger something to PrimitiveBatch will renderer anything...
	m_sprites->Begin(DirectX::SpriteSortMode::SpriteSortMode_Immediate, NonPremultiplied);
	RECT rect{ 0,0,0,0 };
	XMVECTORF32 color;
	m_sprites->Draw(m_nullTexture.Get(), rect, nullptr, color);
	m_sprites->End();
	
	ID3D11ShaderResourceView* nullTexture(m_nullTexture.Get());

	m_batch->Begin(nullTexture);

	bool isSpriteBatchLast = true;
	int size = mBatch.size();
	for (size_t i = 0; i < size; i++)
	{
		Batch& item = mBatch[i];
	
		bool isSpriteBatch = item.Type != Batch::ShapeType::Triangles;
	
		if (isSpriteBatch)
		{
			RECT rect;
			rect.left = item.rectangle.X;
			rect.top = item.rectangle.Y;
			rect.right = item.rectangle.Z;
			rect.bottom = item.rectangle.W;
			
			XMVECTORF32 color =
			{
				// TODO: Optimize this (Wp8 has not this problem to multiply, Why?)
				item.color.R * 0.003921568627451,
				item.color.G * 0.003921568627451,
				item.color.B * 0.003921568627451,
				item.color.A * 0.003921568627451
			};
			
			if (item.textureId > -1)
			{
				if (item.Type == Batch::ShapeType::Rectangle) // Rectangle.
				{
					RECT sourceRectangle;

					sourceRectangle.left = item.textureCoords.X;
					sourceRectangle.top = item.textureCoords.Y;
					sourceRectangle.right = item.textureCoords.Z;
					sourceRectangle.bottom = item.textureCoords.W;
					
					XMFLOAT4 col{
						item.color.R * 0.003921568627451f,
						item.color.G * 0.003921568627451f,
						item.color.B * 0.003921568627451f,
						item.color.A * 0.003921568627451f };

					DirectX::VertexPositionColorTexture v1(
						XMFLOAT3{ (float)item.rectangle.X, (float)item.rectangle.Y, 0 },
						col,
						XMFLOAT2{ (float)item.textureCoords.X, (float)item.textureCoords.Y });
					DirectX::VertexPositionColorTexture v2(
						XMFLOAT3{ (float)item.rectangle.Z, (float)item.rectangle.Y, 0 },
						col,
						XMFLOAT2{ (float)item.textureCoords.Z, (float)item.textureCoords.Y });
					DirectX::VertexPositionColorTexture v3(
						XMFLOAT3{ (float)item.rectangle.Z, (float)item.rectangle.W, 0 },
						col,
						XMFLOAT2{ (float)item.textureCoords.Z, (float)item.textureCoords.W });
					DirectX::VertexPositionColorTexture v4(
						XMFLOAT3{ (float)item.rectangle.X, (float)item.rectangle.W, 0 },
						col,
						XMFLOAT2{ (float)item.textureCoords.X, (float)item.textureCoords.W });

					// Texture.
					m_batch->End();
					m_batch->Begin(m_textures[item.textureId]);
					m_batch->DrawQuad(v1, v2, v3, v4);
					m_batch->End();
					m_batch->Begin(nullTexture);
				}
			}
			else
			{
				XMFLOAT4 col{
					item.color.R * 0.003921568627451f,
					item.color.G * 0.003921568627451f,
					item.color.B * 0.003921568627451f,
					item.color.A * 0.003921568627451f };

				if (item.Type == Batch::ShapeType::Rectangle)
				{
					DirectX::VertexPositionColorTexture v1(
						XMFLOAT3{ (float)rect.left, (float)rect.top, 0 },
						col,
						XMFLOAT2());
					DirectX::VertexPositionColorTexture v2(
						XMFLOAT3{ (float)rect.left, (float)rect.bottom, 0 },
						col,
						XMFLOAT2());
					DirectX::VertexPositionColorTexture v3(
						XMFLOAT3{ (float)rect.right, (float)rect.bottom, 0 },
						col,
						XMFLOAT2());
					DirectX::VertexPositionColorTexture v4(
						XMFLOAT3{ (float)rect.right, (float)rect.top, 0 },
						col,
						XMFLOAT2());

					// Texture.
					m_batch->DrawQuad(v1, v2, v3, v4);
				}
				else if (item.Type == Batch::ShapeType::Line) 
				{
					// Start.
					SharpDepend_UWP_DirectXInterop::Vector2Double tl{item.rectangle.X, item.rectangle.Y};
					SharpDepend_UWP_DirectXInterop::Vector2Double bl{item.rectangle.X, item.rectangle.Y};

					// Stop.
					SharpDepend_UWP_DirectXInterop::Vector2Double tr{item.rectangle.Z, item.rectangle.W};
					SharpDepend_UWP_DirectXInterop::Vector2Double br{item.rectangle.Z, item.rectangle.W};

					double xDiff = tr.X - tl.X;
					double yDiff = tr.Y - tl.Y;
					double value = -atan2(yDiff, xDiff);
					double thickness = 1.5;

					tl.X += (float)(sin(value) * thickness);
					tl.Y += (float)(cos(value) * thickness);
					bl.X -= (float)(sin(value) * thickness);
					bl.Y -= (float)(cos(value) * thickness);

					tr.X += (float)(sin(value) * thickness);
					tr.Y += (float)(cos(value) * thickness);
					br.X -= (float)(sin(value) * thickness);
					br.Y -= (float)(cos(value) * thickness);

					DirectX::VertexPositionColorTexture v1(
						XMFLOAT3{ (float)tl.X, (float)tl.Y, 0 },
						col,
						XMFLOAT2());
					DirectX::VertexPositionColorTexture v2(
						XMFLOAT3{ (float)bl.X, (float)bl.Y, 0 },
						col,
						XMFLOAT2());
					DirectX::VertexPositionColorTexture v3(
						XMFLOAT3{ (float)br.X, (float)br.Y, 0 },
						col,
						XMFLOAT2());
					DirectX::VertexPositionColorTexture v4(
						XMFLOAT3{ (float)tr.X, (float)tr.Y, 0 },
						col,
						XMFLOAT2());

					// Texture.
					m_batch->DrawQuad(v1, v2, v3, v4);
				}
				else if (item.Type == Batch::ShapeType::Circle)
				{
					double radian = item.rectangle.Z;
					int corners = min(8, (int)radian);

					DirectX::VertexPositionColorTexture cCenter(
						XMFLOAT3{ (float)item.rectangle.X, (float)item.rectangle.Y, 0 },
						col,
						XMFLOAT2());
					DirectX::VertexPositionColorTexture cFirst;
					DirectX::VertexPositionColorTexture cLast;

					for (size_t i = 0; i < corners; i++)
					{
						// Vertices.
						double angle = (3.14 * 2) / corners * i;
						double x = ::sin(angle) * radian + item.rectangle.X;
						double y = ::cos(angle) * radian + item.rectangle.Y;

						DirectX::VertexPositionColorTexture v1(
							XMFLOAT3{ (float)x, (float)y, 0 },
							col,
							XMFLOAT2());

						if (i != 0)
						{
							m_batch->DrawTriangle(cCenter, v1, cLast);
						}
						else
						{
							cFirst = v1;
						}

						cLast = v1;
					}

					m_batch->DrawTriangle(cCenter, cFirst, cLast);
				}
			}
		}
		else
		{
			for (size_t j = 0; j < item.indicesLength; j += 3)
			{			
				auto& vert0(item.vertices[item.indices[j + 0]]);
				auto& vert1(item.vertices[item.indices[j + 1]]);
				auto& vert2(item.vertices[item.indices[j + 2]]);
			
				auto& col0(item.colors[item.indices[j + 0]]);
				auto& col1(item.colors[item.indices[j + 1]]);
				auto& col2(item.colors[item.indices[j + 2]]);
			
				DirectX::VertexPositionColorTexture v1(XMFLOAT3{ (float)vert0.X, (float)vert0.Y, 0 }, XMFLOAT4{ col0.R / 255.0f, col0.G / 255.0f, col0.B / 255.0f, col0.A / 255.0f }, XMFLOAT2());
				DirectX::VertexPositionColorTexture v2(XMFLOAT3{ (float)vert1.X, (float)vert1.Y, 0 }, XMFLOAT4{ col1.R / 255.0f, col1.G / 255.0f, col1.B / 255.0f, col1.A / 255.0f }, XMFLOAT2());
				DirectX::VertexPositionColorTexture v3(XMFLOAT3{ (float)vert2.X, (float)vert2.Y, 0 }, XMFLOAT4{ col2.R / 255.0f, col2.G / 255.0f, col2.B / 255.0f, col2.A / 255.0f }, XMFLOAT2());

				// Texture.
				m_batch->DrawTriangle(v1, v2, v3);
			}
		}
	}

	m_batch->End();

	//if (isSpriteBatchLast)
	//{
	//	m_sprites->End();
	//}
	//else
	//{
	//	m_batch->End();
	//}

	mBatch.clear();

	Present();

	mMutes.unlock();
}
*/

const float midnightBlue[] = { 0.0f, 0.0f, 0.0f, 1.000f };

void SharpDepend_UWP_DirectXInterop::D3DPanel::OnBeginDraw()
{
	//mBatch.clear();

	// Only draw the cube once it is loaded (loading is asynchronous).
	if (!m_loadingComplete)
	{
		return;
	}

	m_d3dContext->ClearRenderTargetView(
		m_renderTargetView.Get(),
		midnightBlue
	);

	m_d3dContext->ClearDepthStencilView(
		m_depthStencilView.Get(),
		D3D11_CLEAR_DEPTH,
		1.0f,
		0
	);

	m_d3dContext->OMSetRenderTargets(
		1,
		m_renderTargetView.GetAddressOf(),
		m_depthStencilView.Get()
	);

	// Just to trigger something to PrimitiveBatch will renderer anything...
	m_sprites->Begin(DirectX::SpriteSortMode::SpriteSortMode_Immediate, NonPremultiplied);
	RECT rect;
	rect.bottom = 0;
	rect.left = 0;
	rect.right = 0;
	rect.top = 0;
	XMVECTORF32 color;
	m_sprites->Draw(m_nullTexture.Get(), rect, nullptr, color);
	m_sprites->End();

	m_batch->Begin(m_nullTexture.Get());
}

void SharpDepend_UWP_DirectXInterop::D3DPanel::OnDrawRectangle(
	float x1, float y1, float x2, float y2,
	float r, float g, float b, float a,
	int textureId,
	float td_x1, float td_y1, float td_x2, float td_y2,
	int textureWidth, int textureHeight)
{
	RECT rect;
	rect.left = x1;
	rect.top = y1;
	rect.right = x2;
	rect.bottom = y2;
	XMFLOAT4 col;
	col.x = r* 0.003921568627451;
	col.y = g* 0.003921568627451;
	col.z = b* 0.003921568627451;
	col.w = a* 0.003921568627451;
	XMFLOAT4 sourceRectangle;

	sourceRectangle.x = (float)(1.0 / textureWidth * td_x1);
	sourceRectangle.y = (float)(1.0 / textureHeight * td_y1);
	sourceRectangle.z = (float)(1.0 / textureWidth * td_x2);
	sourceRectangle.w = (float)(1.0 / textureHeight * td_y2);

	DirectX::VertexPositionColorTexture v1(
		XMFLOAT3((float)rect.left, (float)rect.top, 0),
		col,
		XMFLOAT2(sourceRectangle.x, sourceRectangle.y));
	DirectX::VertexPositionColorTexture v2(
		XMFLOAT3((float)rect.right, (float)rect.top, 0),
		col,
		XMFLOAT2(sourceRectangle.z, sourceRectangle.y));
	DirectX::VertexPositionColorTexture v3(
		XMFLOAT3((float)rect.right, (float)rect.bottom, 0),
		col,
		XMFLOAT2(sourceRectangle.z, sourceRectangle.w));
	DirectX::VertexPositionColorTexture v4(
		XMFLOAT3((float)rect.left, (float)rect.bottom, 0),
		col,
		XMFLOAT2(sourceRectangle.x, sourceRectangle.w));

	if (textureId > -1)
	{
		m_batch->End();
		m_batch->Begin(m_textures[textureId]);
		m_batch->DrawQuad(v1, v2, v3, v4);
		m_batch->End();
		m_batch->Begin(m_nullTexture.Get());
	}
	else
	{
		m_batch->End();
		m_batch->Begin(m_nullTexture.Get());
		m_batch->DrawQuad(v1, v2, v3, v4);
		m_batch->End();
		m_batch->Begin(m_nullTexture.Get());
	}
}

void SharpDepend_UWP_DirectXInterop::D3DPanel::OnDrawLine(
	float x1, float y1, float x2, float y2,
	float r, float g, float b, float a)
{
	XMFLOAT4 col;
	col.x = r* 0.003921568627451;
	col.y = g* 0.003921568627451;
	col.z = b* 0.003921568627451;
	col.w = a* 0.003921568627451;
	// Start.
	Vector2 tl;
	tl.X = x1;
	tl.Y = y1;
	Vector2 bl;
	bl.X = x1;
	bl.Y = y1;

	// Stop.
	Vector2 tr;
	tr.X = x2;
	tr.Y = y2;
	Vector2 br;
	br.X = x2;
	br.Y = y2;

	double xDiff = tr.X - tl.X;
	double yDiff = tr.Y - tl.Y;
	double value = -atan2(yDiff, xDiff);
	double thickness = 1.5;

	tl.X += (float)(sin(value) * thickness);
	tl.Y += (float)(cos(value) * thickness);
	bl.X -= (float)(sin(value) * thickness);
	bl.Y -= (float)(cos(value) * thickness);

	tr.X += (float)(sin(value) * thickness);
	tr.Y += (float)(cos(value) * thickness);
	br.X -= (float)(sin(value) * thickness);
	br.Y -= (float)(cos(value) * thickness);

	DirectX::VertexPositionColorTexture v1(
		XMFLOAT3((float)tl.X, (float)tl.Y, 0),
		col,
		XMFLOAT2());
	DirectX::VertexPositionColorTexture v2(
		XMFLOAT3((float)bl.X, (float)bl.Y, 0),
		col,
		XMFLOAT2());
	DirectX::VertexPositionColorTexture v3(
		XMFLOAT3((float)br.X, (float)br.Y, 0),
		col,
		XMFLOAT2());
	DirectX::VertexPositionColorTexture v4(
		XMFLOAT3((float)tr.X, (float)tr.Y, 0),
		col,
		XMFLOAT2());

	// Texture.
	m_batch->DrawQuad(v1, v2, v3, v4);
}

void SharpDepend_UWP_DirectXInterop::D3DPanel::OnDrawCircle(
	float x, float y, float radius,
	float r, float g, float b, float a)
{
	XMFLOAT4 col;
	col.x = r* 0.003921568627451;
	col.y = g* 0.003921568627451;
	col.z = b* 0.003921568627451;
	col.w = a* 0.003921568627451;

	int corners = min(8, (int)radius);

	DirectX::VertexPositionColorTexture cCenter(
		XMFLOAT3((float)x, (float)y, 0),
		col,
		XMFLOAT2());
	DirectX::VertexPositionColorTexture cFirst;
	DirectX::VertexPositionColorTexture cLast;

	for (size_t i = 0; i < corners; i++)
	{
		// Vertices.
		double angle = (3.14 * 2) / corners * i;
		double x_ = ::sin(angle) * radius + x;
		double y_ = ::cos(angle) * radius + y;

		DirectX::VertexPositionColorTexture v1(
			XMFLOAT3((float)x_, (float)y_, 0),
			col,
			XMFLOAT2());

		if (i != 0)
		{
			m_batch->DrawTriangle(cCenter, v1, cLast);
		}
		else
		{
			cFirst = v1;
		}

		cLast = v1;
	}

	m_batch->DrawTriangle(cCenter, cFirst, cLast);
}

void SharpDepend_UWP_DirectXInterop::D3DPanel::OnDrawTriangles(Vector2Double* vertices, int verticesLength, unsigned short* indices, int indicesLength, ColorUInt* colors, int colorLength)
{
	for (size_t j = 0; j < indicesLength; j += 3)
	{
		auto& vert0(vertices[indices[j + 0]]);
		auto& vert1(vertices[indices[j + 1]]);
		auto& vert2(vertices[indices[j + 2]]);

		auto& col0(colors[indices[j + 0]]);
		auto& col1(colors[indices[j + 1]]);
		auto& col2(colors[indices[j + 2]]);

		DirectX::VertexPositionColorTexture v1(XMFLOAT3((float)vert0.X, (float)vert0.Y, 0), XMFLOAT4(col0.R / 255.0f, col0.G / 255.0f, col0.B / 255.0f, col0.A / 255.0f), XMFLOAT2());
		DirectX::VertexPositionColorTexture v2(XMFLOAT3((float)vert1.X, (float)vert1.Y, 0), XMFLOAT4(col1.R / 255.0f, col1.G / 255.0f, col1.B / 255.0f, col1.A / 255.0f), XMFLOAT2());
		DirectX::VertexPositionColorTexture v3(XMFLOAT3((float)vert2.X, (float)vert2.Y, 0), XMFLOAT4(col2.R / 255.0f, col2.G / 255.0f, col2.B / 255.0f, col2.A / 255.0f), XMFLOAT2());

		// Texture.
		m_batch->DrawTriangle(v1, v2, v3);
	}
}

void SharpDepend_UWP_DirectXInterop::D3DPanel::OnEndDraw()
{
	m_batch->End();

	Present();
}












void SharpDepend_UWP_DirectXInterop::D3DPanel::OnRegisterTexture(int id, int * data, int dataLength, int width, int height)
{
	mMutes.lock();
	if (m_textures.count(id))
	{
		mMutes.unlock();
		throw "Texture id already exist.";
	}

	m_textures[id] = CreateSquareTexture(width, height, data);
	mMutes.unlock();
}

void SharpDepend_UWP_DirectXInterop::D3DPanel::OnUnregisterTexture(int id)
{
	mMutes.lock();
	m_textures[id]->Release();
	m_textures.erase(id);
	mMutes.unlock();
}

void SharpDepend_UWP_DirectXInterop::D3DPanel::OnUpdateTexture(int id, int* data, int width, int height)
{
	mMutes.lock();
	auto texture = m_textures[id];

	int size = sizeof(int) * width;

	ID3D11Resource* res = nullptr;
	texture->GetResource(&res);

	m_d3dContext->UpdateSubresource(res, 0, nullptr, data, size, 0);
	mMutes.unlock();
}

void D3DPanel::CreateDeviceResources()
{
	mMutes.lock();
    DirectXPanelBase::CreateDeviceResources();
	
    // Retrieve DXGIOutput representing the main adapter output.
    ComPtr<IDXGIFactory1> dxgiFactory;
    ThrowIfFailed(
        CreateDXGIFactory1(IID_PPV_ARGS(&dxgiFactory))
        );
	
    ComPtr<IDXGIAdapter> dxgiAdapter;
    ThrowIfFailed(
        dxgiFactory->EnumAdapters(0, &dxgiAdapter)
        );
	
    ThrowIfFailed(
        dxgiAdapter->EnumOutputs(0, &m_dxgiOutput)
        );
	
    // Asynchronously load vertex shader and create input layout.
    auto loadVSTask = DX::ReadDataAsync(L"SharpDepend_UWP_DirectXInterop\\SimpleVertexShader.cso");
    auto createVSTask = loadVSTask.then([this](const std::vector<byte>& fileData) {
        ThrowIfFailed(
            m_d3dDevice->CreateVertexShader(
            &fileData[0],
            fileData.size(),
            nullptr,
            &m_vertexShader
            )
            );
	
        static const D3D11_INPUT_ELEMENT_DESC vertexDesc [] =
        {
            { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
            { "COLOR", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 },
        };
	
        ThrowIfFailed(
            m_d3dDevice->CreateInputLayout(
            vertexDesc,
            ARRAYSIZE(vertexDesc),
            &fileData[0],
            fileData.size(),
            &m_inputLayout
            )
            );
    });
	
    // Asynchronously load vertex shader and create constant buffer.
    auto loadPSTask = DX::ReadDataAsync(L"SharpDepend_UWP_DirectXInterop\\SimplePixelShader.cso");
    auto createPSTask = loadPSTask.then([this](const std::vector<byte>& fileData) {
        ThrowIfFailed(
            m_d3dDevice->CreatePixelShader(
            &fileData[0],
            fileData.size(),
            nullptr,
            &m_pixelShader
            )
            );
	
        CD3D11_BUFFER_DESC constantBufferDesc(sizeof(ModelViewProjectionConstantBuffer), D3D11_BIND_CONSTANT_BUFFER);
        ThrowIfFailed(
            m_d3dDevice->CreateBuffer(
            &constantBufferDesc,
            nullptr,
            &m_constantBuffer
            )
            );
    });
	
    // Once both shaders are loaded, create the mesh.
    auto createCubeTask = (createPSTask && createVSTask).then([this]() {
	
        // Load mesh vertices. Each vertex has a position and a color.
        static const DX::VertexPositionColor cubeVertices [] =
        {
            {XMFLOAT3(-0.5f, -0.5f, -0.5f), XMFLOAT3(0.0f, 0.0f, 0.0f)},
            { XMFLOAT3(-0.5f, -0.5f, 0.5f), XMFLOAT3(0.0f, 0.0f, 1.0f) },
            { XMFLOAT3(-0.5f, 0.5f, -0.5f), XMFLOAT3(0.0f, 1.0f, 0.0f) },
            { XMFLOAT3(-0.5f, 0.5f, 0.5f), XMFLOAT3(0.0f, 1.0f, 1.0f) },
            { XMFLOAT3(0.5f, -0.5f, -0.5f), XMFLOAT3(1.0f, 0.0f, 0.0f) },
            { XMFLOAT3(0.5f, -0.5f, 0.5f), XMFLOAT3(1.0f, 0.0f, 1.0f) },
            { XMFLOAT3(0.5f, 0.5f, -0.5f), XMFLOAT3(1.0f, 1.0f, 0.0f) },
            { XMFLOAT3(0.5f, 0.5f, 0.5f), XMFLOAT3(1.0f, 1.0f, 1.0f) },
        };
	
        D3D11_SUBRESOURCE_DATA vertexBufferData = { 0 };
        vertexBufferData.pSysMem = cubeVertices;
        vertexBufferData.SysMemPitch = 0;
        vertexBufferData.SysMemSlicePitch = 0;
        CD3D11_BUFFER_DESC vertexBufferDesc(sizeof(cubeVertices), D3D11_BIND_VERTEX_BUFFER);
        ThrowIfFailed(
            m_d3dDevice->CreateBuffer(
            &vertexBufferDesc,
            &vertexBufferData,
            &m_vertexBuffer
            )
            );
	
        // Load mesh indices. Each triple of indices represents
        // a triangle to be rendered on the screen.
        // For example, 0,2,1 means that the vertices with indexes
        // 0, 2 and 1 from the vertex buffer compose the 
        // first triangle of this mesh.
        static const unsigned short cubeIndices [] =
        {
            0, 2, 1, // -x
            1, 2, 3,
	
            4, 5, 6, // +x
            5, 7, 6,
	
            0, 1, 5, // -y
            0, 5, 4,
	
            2, 6, 7, // +y
            2, 7, 3,
	
            0, 4, 6, // -z
            0, 6, 2,
	
            1, 3, 7, // +z
            1, 7, 5,
        };
	
        m_indexCount = ARRAYSIZE(cubeIndices);
	
        D3D11_SUBRESOURCE_DATA indexBufferData = { 0 };
        indexBufferData.pSysMem = cubeIndices;
        indexBufferData.SysMemPitch = 0;
        indexBufferData.SysMemSlicePitch = 0;
        CD3D11_BUFFER_DESC indexBufferDesc(sizeof(cubeIndices), D3D11_BIND_INDEX_BUFFER);
        ThrowIfFailed(
            m_d3dDevice->CreateBuffer(
            &indexBufferDesc,
            &indexBufferData,
            &m_indexBuffer
            )
            );
    });
	
    // Once the cube is loaded, the object is ready to be rendered.
    createCubeTask.then([this]() {
        m_loadingComplete = true;
    });

	///////////////////////////////////////////////////////////////////////////////////////////
	///////////////////////////////////////////////////////////////////////////////////////////

	//DirectXPanelBase::CreateDeviceResources();

	// Create DirectXTK objects
	auto device = m_d3dDevice.Get();
	m_states.reset(new CommonStates(device));
	
	CommonStates states(device);
	NonPremultiplied = states.NonPremultiplied();
	
	auto context = m_d3dContext.Get();
	m_sprites.reset(new SpriteBatch(context));
	m_batch.reset(new PrimitiveBatch<DirectX::VertexPositionColorTexture>(context));
	
	m_batchEffect.reset(new BasicEffect(device));
	m_batchEffect->SetVertexColorEnabled(true);
	
	{
		void const* shaderByteCode;
		size_t byteCodeLength;
	
		m_batchEffect->GetVertexShaderBytecode(&shaderByteCode, &byteCodeLength);
	
		ThrowIfFailed(
			device->CreateInputLayout(DirectX::VertexPositionColor::InputElements,
				DirectX::VertexPositionColor::InputElementCount,
				shaderByteCode, byteCodeLength,
				m_batchInputLayout.ReleaseAndGetAddressOf())
			);
	}
	
	int* pixel = new int[1];
	pixel[0] = -1;
	m_nullTexture = CreateSquareTexture(1, 1, pixel);
	delete pixel;

	mMutes.unlock();
}

/// Reference: https://msdn.microsoft.com/en-us/library/windows/desktop/ff476521(v=vs.85).aspx
/// Mipmaps: https://msdn.microsoft.com/en-us/library/windows/desktop/ff476426(v=vs.85).aspx
ID3D11ShaderResourceView* D3DPanel::CreateSquareTexture(int width, int height, int* texArray)
{
	auto device = m_d3dDevice.Get();

	int size = sizeof(int);
	int length = size * width * height;

	ID3D11Texture2D *boxTex = 0;

	D3D11_TEXTURE2D_DESC boxTexDesc;
	ZeroMemory(&boxTexDesc, sizeof(D3D11_TEXTURE2D_DESC));
	boxTexDesc.ArraySize = 1;
	boxTexDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET;
	boxTexDesc.CPUAccessFlags = 0;
	boxTexDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
	boxTexDesc.Height = height;
	boxTexDesc.MipLevels = 1;
	boxTexDesc.MiscFlags = D3D11_RESOURCE_MISC_GENERATE_MIPS;
	boxTexDesc.SampleDesc.Count = 1;
	boxTexDesc.SampleDesc.Quality = 0; // m_4xMsaaQuality - 1;
	boxTexDesc.Usage = D3D11_USAGE_DEFAULT;
	boxTexDesc.Width = width;
	
	D3D11_SUBRESOURCE_DATA boxTexInitData;
	//D3D11_MAPPED_SUBRESOURCE boxTexInitData;
	ZeroMemory(&boxTexInitData, sizeof(D3D11_SUBRESOURCE_DATA));
	boxTexInitData.pSysMem = texArray;
	boxTexInitData.SysMemPitch = size * width;

	ID3D11ShaderResourceView* texture = nullptr;

	auto h1 = m_d3dDevice->CreateTexture2D(&boxTexDesc, &boxTexInitData, &boxTex);
	auto h2 = m_d3dDevice->CreateShaderResourceView(boxTex, NULL, &texture);
	
	m_d3dContext->GenerateMips(texture);

	return texture;
}

void D3DPanel::CreateSizeDependentResources()
{
	mMutes.lock();
	DirectXPanelBase::CreateSizeDependentResources();
	
	float aspectRatio = m_width / m_height;
	float fovAngleY = 70.0f * XM_PI / 180.0f;
	if (aspectRatio < 1.0f)
	{
		fovAngleY /= aspectRatio;
	}
	
	// Note that the m_orientationTransform3D matrix is post-multiplied here
	// in order to correctly orient the scene to match the display orientation.
	// This post-multiplication step is required for any draw calls that are
	// made to the swap chain render target. For draw calls to other targets,
	// this transform should not be applied.
	
	XMMATRIX projection =
		XMMatrixMultiply(
			XMMatrixPerspectiveFovRH(
				fovAngleY,
				aspectRatio,
				0.01f,
				100.0f
				),
			XMLoadFloat4x4(&m_orientationTransform3D));
	
	m_batchEffect->SetProjection(projection);
	
	XMStoreFloat4x4(&m_projection, projection);
	
	///////////////////////////////////////////////////////////////////////////////////////////
	///////////////////////////////////////////////////////////////////////////////////////////

    m_renderTargetView = nullptr;
    m_depthStencilView = nullptr;
	
    //DirectXPanelBase::CreateSizeDependentResources();
	
    // Create a render target view of the swap chain back buffer.
    ComPtr<ID3D11Texture2D> backBuffer;
    ThrowIfFailed(
        m_swapChain->GetBuffer(0, IID_PPV_ARGS(&backBuffer))
        );
	
    // Create render target view.
    ThrowIfFailed(
        m_d3dDevice->CreateRenderTargetView(
        backBuffer.Get(),
        nullptr,
        &m_renderTargetView)
        );
	
    // Create and set viewport.
    D3D11_VIEWPORT viewport = CD3D11_VIEWPORT(
        0.0f,
        0.0f,
        m_renderTargetWidth,
        m_renderTargetHeight
        );
	
    m_d3dContext->RSSetViewports(1, &viewport);
	
    // Create depth/stencil buffer descriptor.
    CD3D11_TEXTURE2D_DESC depthStencilDesc(
        DXGI_FORMAT_D24_UNORM_S8_UINT,
        static_cast<UINT>(m_renderTargetWidth),
        static_cast<UINT>(m_renderTargetHeight),
        1,
        1,
        D3D11_BIND_DEPTH_STENCIL
        );
	
    // Allocate a 2-D surface as the depth/stencil buffer.
    ComPtr<ID3D11Texture2D> depthStencil;
    ThrowIfFailed(
        m_d3dDevice->CreateTexture2D(&depthStencilDesc, nullptr, &depthStencil)
        );
	
    // Create depth/stencil view based on depth/stencil buffer.
    const CD3D11_DEPTH_STENCIL_VIEW_DESC depthStencilViewDesc = CD3D11_DEPTH_STENCIL_VIEW_DESC(D3D11_DSV_DIMENSION_TEXTURE2D);
    ThrowIfFailed(
        m_d3dDevice->CreateDepthStencilView(
        depthStencil.Get(),
        &depthStencilViewDesc,
        &m_depthStencilView
        )
        );
	mMutes.unlock();
}